<template>
  <teleport to="body">
    <div v-if="type === FULLSCREEN_PHOTO_TYPE.MULTIPLE" class="waterful-photo bg-background">
      <div class="photos gap-col-8" @scroll="onScroll">
        <div class="photo" v-for="(photo, i) in showPhotos" :key="i" ref="photosRef">
          <EncryptImage :src="photo.url" disable-lazy @img-load="photosMounted[i] = true"></EncryptImage>
          <LockMask
            v-if="photosMounted[i] && showLock && i !== 0"
            :rights="feed.need_rights"
            :is-block="feed.author?.is_block"
            :is-subscribe="feed.need_subscribe"
            :is-buy="feed.need_buy"
            :buy-price="feed.money"
          ></LockMask>
          <WaterMark v-if="showWaterMark"></WaterMark>
        </div>
      </div>
      <div class="head">
        <Icon class="back pointer" size="28" name="back" @click="closeFullscreen"></Icon>
        <Icon
          v-if="isLogin && feed.aff !== selfId"
          class="more pointer"
          size="28"
          name="more"
          @click="more(feed.aff, feed.id)"
        ></Icon>
        <div class="index font-size-14 font-weight-500 line-height-140">
          {{ scrollToIndex + 1 + '/' + photos.length }}
        </div>
      </div>
    </div>
  </teleport>
</template>

<script setup>
import { computed, ref, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useAccountStore } from '@/store/account'
import { useFullscreenPhotoStore } from '@/store/fullscreen-photo'
import WaterMark from '@/components/common/WaterMark.vue'
import EncryptImage from '@/components/multimedia/EncryptImage.vue'
import LockMask from '@/components/viewer/LockMask.vue'
import { useDialog } from '@/compositions/viewer/dialog'
import { FULLSCREEN_PHOTO_TYPE, RIGHTS_TYPE } from '@/constant'

const fulscreenPhotoStore = useFullscreenPhotoStore()
const { type, feed, showWaterMark } = storeToRefs(fulscreenPhotoStore)
const { closeFullscreen } = fulscreenPhotoStore

const showLock = computed(
  () =>
    feed.value.need_rights !== RIGHTS_TYPE.PASS ||
    feed.value.need_subscribe ||
    feed.value.need_buy ||
    feed.value.author?.is_block,
)

const SHOW_STEP = 5
const SCROLL_BOUNDARY_DIST = 100
let prevScrollTop
let isScrollToBottom = false

const photosRef = ref([])

// 真正顯示出的照片數量
const showCount = ref(SHOW_STEP)

// 每張照片是否完成渲染: boolean
const photosMounted = ref([])

// 目前scroll至哪張照片
const scrollToIndex = ref(0)

// 每張照片的 offsetTop: number
const photosTop = ref([])

const photos = computed(() => {
  const firstImg = {
    url: feed.value.img_path,
    width: feed.value.img_width,
    height: feed.value.img_height,
  }
  const imgMoreKey = showLock.value ? 'img_more_blur' : 'img_more'
  if (feed.value[imgMoreKey]) {
    return [firstImg, ...feed.value[imgMoreKey]]
  }
  return [firstImg]
})
const showPhotos = computed(() => photos.value.slice(0, showCount.value))

const viewport = document.querySelector('meta[name=viewport]')
let prevViewportContent
watch(type, (v, prev) => {
  if (v === FULLSCREEN_PHOTO_TYPE.MULTIPLE) {
    showCount.value = SHOW_STEP
    photosMounted.value = photos.value.map(() => false)

    prevViewportContent = viewport.getAttribute('content')
    viewport.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=4, user-scalable=yes')
  }
  if (v === FULLSCREEN_PHOTO_TYPE.CLOSE && prev === FULLSCREEN_PHOTO_TYPE.MULTIPLE) {
    reset()

    viewport.setAttribute('content', prevViewportContent)
  }
})

watch(
  photosMounted,
  (v) => {
    const startIndex = photosTop.value.length
    const endIndex = v.indexOf(false, startIndex)
    if (endIndex >= 0) {
      photosTop.value.push(...photosRef.value.slice(startIndex, endIndex).map((e) => e.offsetTop))
    } else {
      if (startIndex !== 0) {
        photosTop.value.push(...photosRef.value.slice(startIndex).map((e) => e.offsetTop))
      }
    }
  },
  { deep: true },
)

function onScroll({ target: { scrollTop, scrollHeight, clientHeight } }) {
  // 滑到底添加展示圖片
  if (scrollHeight - scrollTop - clientHeight < SCROLL_BOUNDARY_DIST) {
    if (!isScrollToBottom) {
      isScrollToBottom = true
      if (showCount.value < photos.value.length) {
        showCount.value += Math.min(SHOW_STEP, photos.value.length - showCount.value)
      }
    }
  } else {
    isScrollToBottom = false
  }

  const delta = scrollTop - (prevScrollTop || scrollTop)
  prevScrollTop = scrollTop

  // 上滑更新索引標籤
  if (delta < 0) {
    if (scrollToIndex.value === 1) {
      if (scrollTop < SCROLL_BOUNDARY_DIST) {
        scrollToIndex.value -= 1
      }
    } else {
      const prev = photosTop.value[scrollToIndex.value - 1]
      if (prev && prev >= scrollTop + SCROLL_BOUNDARY_DIST && scrollToIndex.value !== 0) {
        scrollToIndex.value -= 1
      }
    }
  }
  // 下滑更新索引標籤
  else {
    const next = photosTop.value[scrollToIndex.value + 1]
    if (next && scrollTop + SCROLL_BOUNDARY_DIST >= next && scrollToIndex.value !== photosTop.value.length - 1) {
      scrollToIndex.value += 1
    }
  }
}

function reset() {
  photosMounted.value = []
  scrollToIndex.value = 0
  photosTop.value = []
  prevScrollTop = null
  isScrollToBottom = false
}

const accountStore = useAccountStore()
const { isLogin, userId: selfId } = storeToRefs(accountStore)
const { more } = useDialog()
</script>

<style lang="scss" scoped>
.waterful-photo {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  z-index: 1; // MediaWall.vue 當中的 tab sticky 時需要設定 z-index，會跟這邊衝突所以這邊也得設定至少同層級

  .photos {
    width: 100%;
    max-width: 960px;
    height: 100%;
    overflow: auto;
    display: flex;
    flex-direction: column;
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);

    .photo {
      position: relative;
    }
  }

  .head {
    pointer-events: none;
    width: 100%;
    height: 9.3125rem;
    padding: 0.75rem 1rem 1.125rem;
    position: absolute;
    top: 0;
    background: linear-gradient(to bottom, rgba(65, 65, 65, 0.46) -5.88%, rgba(65, 65, 65, 0) 71.81%);

    .back,
    .more,
    .index {
      pointer-events: initial;
      position: absolute;
    }

    .back {
      left: 1rem;
    }

    .more {
      right: 1rem;
    }

    .index {
      width: fit-content;
      padding: 0 0.6875rem;
      border-radius: 0.628125rem;
      background: rgba(115, 115, 115, 0.5);
      top: 4.375rem;
      right: 1.25rem;
    }
  }
}
</style>
